<?php

namespace Lib;

class Template {
	private $_sTplPath;
	private $_sTmpPath;
	private $_sFilePre = '';
	private $_aVars = array ();

	public function __construct($aConf = array()) {
		$this->init ( $aConf );
	}

	public function init($aConf = array()) {
		global $_CONFIG;
		$aConf += ( array ) $_CONFIG ['template'];
		$this->_sTplPath = ROOT . '/' . $aConf ['tpl_path'];
		if ($aConf ['name']) {
			$this->_sFilePre = $aConf ['name'] . '_';
			$this->_sTplPath .= '/' . $aConf ['name'];
		} else {
			$this->_sFilePre = 'default_';
			$this->_sTplPath .= '/default';
		}
		$this->_sTmpPath = ROOT . '/' . $aConf ['tmp_path'];
	}

	public function assign($sName, $sVal) {
		$this->_aVars [$sName] = $sVal;
	}

	public function output($sTplFile, $sHtmlFile = null) {
		global $_CONFIG;
		$this->assign ( '_CONFIG', $_CONFIG );
		if ($sTplFile != null) {
			$this->_create ( $sTplFile );
		}
		eval ( 'global $o;' );
		foreach ( $this->_aVars as $sKey => $sRow ) {
			eval ( 'global $' . $sKey . ';' );
			eval ( '$' . $sKey . ' = ' . var_export ( $sRow, true ) . ';' );
		}
		
		if ($sHtmlFile) {
			ob_start ();
		}
		include $this->_sTmpPath . '/' . $this->_sFilePre . str_replace ( '/', '_', $sTplFile ) . '.php';
		if ($sHtmlFile) {
			$this->_writeHtml ();
			ob_end_flush ();
		}
	}

	public function _create($sTplFile) {
		$sTmpFile = $this->_sTmpPath . '/' . $this->_sFilePre . str_replace ( '/', '_', $sTplFile ) . '.php';
		$sTplFile = $this->_sTplPath . '/' . $sTplFile;
		if (is_file ( $sTmpFile ) && @filemtime ( $sTplFile ) < @filemtime ( $sTmpFile )) {
			$rFp = fopen ( $sTmpFile, 'r' );
			$sLine = fgets ( $rFp );
			if (preg_match ( '/<\?php \/\*include\:(.+?)\*\/\?>/', $sLine, $aMatch )) {
				$aFile = explode ( ';', $aMatch [1] );
				foreach ( $aFile as $v ) {
					$this->_create ( $v );
				}
			}
			fclose ( $rFp );
			return true;
		}
		if (is_file ( $sTmpFile )) {
			touch ( $sTmpFile, time () + 1 );
		}
		$sTpl = $this->_parse ( $sTplFile );
		try {
			if (! is_dir ( dirname ( $sTmpFile ) )) {
				throw new ExceptionExt ( '模版临时目录' . dirname ( $sTmpFile ) . '不存在' );
			}
			file_put_contents ( $sTmpFile, $sTpl );
		} catch ( ExceptionExt $e ) {
			$e->showError ();
		}
		return true;
	}

	private function _parse($sFile) {
		try {
			$sTpl = @file_get_contents ( $sFile );
			if ($sTpl == false) {
				throw new ExceptionExt ( '模板文件' . $sFile . '不存在' );
			}
			if (preg_match_all ( '/\{template\:(.+?)\}/i', $sTpl, $aMatch )) {
				$aInclude = array_unique ( $aMatch [1] );
				foreach ( $aInclude as $v ) {
					$this->_create ( $v );
				}
				$sInclude = '<?php /*include:' . implode ( ';', $aInclude ) . '*/?>' . "\n";
			}
			$sTpl = preg_replace ( '/\<\!\-\-\{(.+?)\}\-\-\>/s', '{\\1}', $sTpl );
			$sTpl = preg_replace ( '/\{template\:(.+?)\}/is', '<?php include \'' . $this->_sTmpPath . '/' . $this->_sFilePre . str_replace ( '/', '_', '\\1' ) . '.php\';?>', $sTpl );
			$sTpl = preg_replace ( '/\{html\:(.+?)\:(.+?)\}/is', '<?php echo $o->Html->\\1(\\2);?>', $sTpl );
			$sTpl = preg_replace ( '/\{lang\:(.+?)\}/', '{lang_getValue:\\1}', $sTpl );
			$sTpl = preg_replace ( '/\{(\$[a-zA-Z0-9_\[\]\'\"\$\.\x7f-\xff]+)\}/s', '<?php echo \\1;?>', $sTpl );
			$sTpl = preg_replace ( '/[\n\r\t]*\{elseif\s+(.+?)\}[\n\r\t]*/is', '<?php } elseif (\\1) {?>', $sTpl );
			$sTpl = preg_replace ( '/[\n\r\t]*\{else\}[\n\r\t]*/is', '<?php } else {?>', $sTpl );
			$sTpl = preg_replace ( '/[\n\r\t]*\{echo\s+(.+?)\}[\n\r\t]*/is', '<?php echo \\1;?>', $sTpl );
			$sTpl = preg_replace ( '/[\n\r\t]*\{eval\s+(.+?)\}[\n\r\t]*/is', '<?php \\1;?>', $sTpl );
			$sTpl = preg_replace_callback ( '/[\n\r\t]*\{(\$[a-zA-Z0-9_\[\]\'\"\$\.\x7f-\xff]+)=(\w+)\:(.*?)\}[\n\r\t]*/is', array (
					&$this,
					'_callReturn' 
			), $sTpl );
			$sTpl = preg_replace_callback ( '/[\n\r\t]*\{(\w+)\:(.*?)\}[\n\r\t]*/is', array (
					&$this,
					'_call' 
			), $sTpl );
			
			for($i = 0; $i < 5; $i ++) {
				$sTpl = preg_replace ( '/[\n\r\t]*\{foreach\s+(\S+)\s+(\S+)\}[\n\r]*(.+?)[\n\r]*\{\/foreach\}/is', '<?php if(is_array(\\1)){foreach(\\1 as \\2){?>' . "\n" . '\\3' . "\n" . '<?php }}?>' . "\n", $sTpl );
				$sTpl = preg_replace ( '/[\n\r\t]*\{foreach\s+(\S+)\s+(\S+)\s+(\S+)\}[\n\r]*(.+?)[\n\r]*\{\/foreach\}/is', '<?php if(is_array(\\1)){foreach(\\1 as \\2 => \\3){?>' . "\n" . '\\4' . "\n" . '<?php }}?>' . "\n", $sTpl );
				$sTpl = preg_replace ( '/[\n\r\t]*\{foreach\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\}[\n\r]*(.+?)[\n\r]*\{\/foreach\}/is', '<?php if(is_array(\\1)){\\4=0;foreach(\\1 as \\2 => \\3){?>' . "\n" . '\\5' . "\n" . '<?php \\4++;}}?>' . "\n", $sTpl );
				$sTpl = preg_replace ( '/[\n\r\t]*\{if\s+(.+?)\}[\n\r]*(.+?)[\n\r]*\{\/if\}/is', '<?php if(\\1){?>' . '\\2' . '<?php }?>', $sTpl );
			}
		} catch ( ExceptionExt $e ) {
			$e->showError ();
		}
		if ($sInclude) {
			$sTpl = $sInclude . $sTpl;
		}
		return $sTpl;
	}

	private function _callReturn($aMatch) {
		list ( $sClassName, $sMethod, $sType ) = explode ( '_', $aMatch [2] );
		if (! $sType) {
			$sType = 'model';
		} else {
			$sType = strtolower ( $sType );
		}
		if (! $sMethod) {
			$sMethod = '__construct';
		}
		$sClassName = ucfirst ( $sClassName );
		if ($sType == 'lib') {
			return '<?php ' . $aMatch [1] . ' = $o->' . $sClassName . '->' . $sMethod . '(' . $aMatch [2] . ');?>';
		} else {
			return '<?php ' . $aMatch [1] . ' = $o->' . ucfirst ( $sType ) . '->' . $sClassName . '->' . $sMethod . '(' . $aMatch [2] . ');?>';
		}
	}

	private function _call($aMatch) {
		list ( $sClassName, $sMethod, $sType ) = explode ( '_', $aMatch [1] );
		if (! $sType) {
			$sType = 'model';
		} else {
			$sType = strtolower ( $sType );
		}
		if (! $sMethod) {
			$sMethod = '__construct';
		}
		$sClassName = ucfirst ( $sClassName );
		if ($sType == 'lib') {
			return '<?php echo $o->' . $sClassName . '->' . $sMethod . '(' . $aMatch [2] . ');?>';
		} else {
			return '<?php echo = $o->' . ucfirst ( $sType ) . '->' . $sClassName . '->' . $sMethod . '(' . $aMatch [2] . ');?>';
		}
	}
}

?>